home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ian & Stuart's Australian Mac 1993 September
/
September 93.iso
/
Archives
/
Sound
/
MIDI
/
MIDI Utilities
/
CMU Midi Toolkit
/
Source
/
cmdline.c
< prev
next >
Wrap
Text File
|
1988-01-11
|
11KB
|
377 lines
/* cmdline.c -- command line parsing routines
*
* this module is designed to allow various modules to scan (and rescan)
* the command line for applicable arguments. the goal is to hide as
* much information about switches and their names as possible so that
* switches become more consistent across applications and so that the
* author of an application need not do a lot of work to provide numerous
* options. instead, each module scans the command line for its own
* arguments.
*
* command lines are of the following form:
* command -s1 -s2 opt2 -s3 arg1 arg2 -s4 opt4 arg3
*
* note that there are three kinds of command line parameters:
* (1) a switch is a "-" followed by a name, e.g. "-s1"
* (2) an option is a switch followed by a space and name, e.g. "-s2 opt2"
* (3) an argument is a name by itself, e.g. "arg1"
*
* note also that a switch followed by an argument looks just like an
* option, so a list of valid option names is necessary to disambiguate.
*
* a main program that uses cmdline.c should do the following:
* (1) create an array of pointers to strings (char *names[]) that
* contains every possible option name
* (2) create another array of pointers to strings that contains
* every possible switch name
* (2) call cl_init(switches, nsw, options, nopt, argv, argc)
*
* cl_init will report an error (to stderr) if it finds any illegal
* switch or option names.
*
* afterward, switches, options, and arguments can be accessed by
* calling cl_switch, cl_option, and cl_arg. if cl_switch or cl_option
* is called with a switch name that was not mentioned in the call to
* cl_init, an error will result. this indicates that the application
* author omitted a valid switch or option name when calling cl_init.
* this is an error because the full set of names is needed for error
* checking and to distinguish arguments from options.
*
* cl_nswitch and cl_noption are similar to cl_switch and cl_option,
* except they each take a list of equivalent switch or option names.
* this makes it simple to allow both verbose (-debug) and terse (-d) names.
*/
/*****************************************************************************
* Change Log
* Date | Change
*-----------+-----------------------------------------------------------------
* 13-Jun-86 | Created Change Log
* 9-Oct-86 | JMaloney: Modified for Macintosh
* 7-Jan-87 | JMaloney: Converted to Lightspeed C
*****************************************************************************/
#include "switches.h"
#ifdef LIGHTSPEED
#include "Proto.h"
#include <StdIO.h>
#include <Strings.h>
#endif
#ifdef MPW
#include <StdIO.h>
#include <Strings.h>
#endif
#include "cext.h"
#include "cmdline.h"
/*****************************************************************************
*
* variables private to this module
*
*****************************************************************************/
private char **voptions; /* valid options */
private int noptions; /* number of options */
private char **vswitches; /* valid switches */
private int nswitches; /* number of switches */
private char **argv; /* command line argument vector */
private int argc; /* length of argv */
private boolean cl_rdy = false;
/* set to true when initialized */
/*****************************************************************************
*
* routines private to this module
*
*****************************************************************************/
void cl_check_names(char *names[], int nnames, char *valid[], int nvalid);
int cl_find_match(char *names[],int nnames);
int cl_find_string(char *s, char *names[],int nnames);
void cl_ready_check(void);
/*****************************************************************************
* cl_check_names
* Inputs:
* char *names[]: array of alternative switch or option names
* int nnames: number of alternative switch or option names
* char *valid[]: array of valid names
* int nvalid: number of valid names
* Effect:
* checks that all names are in validnames
* if not, print an error message
*****************************************************************************/
private void cl_check_names(names, nnames, valid, nvalid)
char *names[];
int nnames;
char *valid[];
int nvalid;
{
int i;
for (i = 0; i < nnames; i++) {
if (cl_find_string(names[i], valid, nvalid) >= nvalid) {
fprintf(stderr, "internal error detected by cmdline module:\n");
fprintf(stderr, "\t'%s' should be in valid lists\n", names[i]);
}
}
}
/*****************************************************************************
* cl_arg
* Inputs:
* int n: the index of the arg needed
* Results:
* pointer to the nth arg, or NULL if none exists
* arg 0 is the command name
*****************************************************************************/
public char *cl_arg(n)
int n;
{
int i = 1;
if (n <= 0) return argv[0];
while (i < argc) {
if (*argv[i] == '-') {
if (cl_find_string(argv[i], voptions, noptions) < noptions) {
i += 2; /* skip name and option */
} else {
i += 1; /* skip over switch name */
}
} else if (n == 1) {
return argv[i];
} else { /* skip over argument */
n--;
i++;
}
}
return NULL;
}
/*****************************************************************************
* cl_init
* Inputs:
* char *switches[]: array of switch names
* int nsw: number of switch names
* char *options[]: array of option names
* int nopt: number of option names
* char *av: array of command line fields (argv)
* int ac: number of command line fields (argc)
* Returns:
* boolean: true if syntax checks OK, false otherwise
* Effect:
* checks that all command line entries are valid
* saves info for use by other routines
*****************************************************************************/
public boolean cl_init(switches, nsw, options, nopt, av, ac)
char *switches[];
int nsw;
char *options[];
int nopt;
char *av[];
int ac;
{
int i; /* index into argv */
boolean result = true;
vswitches = switches;
nswitches = nsw;
voptions = options;
noptions = nopt;
argv = av;
argc = ac;
for (i = 1; i < argc; i++) { /* case fold lower */
int j;
for (j = 0; j < strlen(argv[i]); j++) {
argv[i][j] = tolower(argv[i][j]);
}
}
/* check command line syntax: */
i = 1;
while (i < argc) {
if (*argv[i] == '-') {
if (cl_find_string(argv[i], voptions, noptions) < noptions) {
i += 1; /* skip name and option */
if (i < argc && *argv[i] == '-') {
fprintf(stderr, "missing argument after %s\n", argv[i-1]);
result = false;
i += 1;
}
} else if (cl_find_string(argv[i], vswitches, nswitches) < nswitches) {
i += 1; /* skip over switch name */
} else {
fprintf(stderr, "invalid switch: %s\n", argv[i]);
i += 1;
result = false;
}
} else i++; /* skip over argument */
}
cl_rdy = true;
return result;
}
/*****************************************************************************
* cl_noption
* Inputs:
* char *names[]: array of alternative switch names
* int nnames: number of alternative switch names
* Result:
* char *: pointer to option if one exists, otherwise null
* Effect:
* looks for pattern in command line of the form "-n s",
* where n is a member of names, and returns pointer to s
* Implementation:
* find the option name, then see if the switch is followed by a
* string that does not start with "-"
*****************************************************************************/
public char *cl_noption(names, nnames)
char *names[];
int nnames;
{
int i; /* index of switch */
cl_ready_check();
cl_check_names(names, nnames, voptions, noptions);
i = cl_find_match(names, nnames) + 1; /* point at the option */
if (i < argc) { /* make sure option exists */
if (*(argv[i]) != '-') return argv[i];
}
return NULL;
}
/*****************************************************************************
* cl_nswitch
* Inputs:
* char *names[]: array of alternative switch names
* int nnames: number of alternative switch names
* Result:
* char *: a pointer to command line switch if one exists,
* NULL otherwise
* Effect:
* checks that names is valid
* finds a pattern in command line of the form "-n",
* where n is a member of names.
*****************************************************************************/
public char *cl_nswitch(names, nnames)
char *names[];
int nnames;
{
int i; /* index of switch */
cl_ready_check();
cl_check_names(names, nnames, vswitches, nswitches);
i = cl_find_match(names, nnames);
if (i < argc) {
return argv[i];
} else {
return NULL;
}
}
/*****************************************************************************
* cl_option
* Inputs:
* char *name: option name
* Returns:
* returns char *: the option string if found, otherwise null
****************************************************************/
public char *cl_option(name)
char *name;
{
char *names[1]; /* array to hold name */
names[0] = name;
return cl_noption(names, 1);
}
/*****************************************************************************
* cl_switch
* Inputs:
* char *name: switch name
* Returns:
* boolean: true if switch found
*****************************************************************************/
public boolean cl_switch(name)
char *name;
{
char *names[1]; /* array to hold name */
names[0] = name;
return cl_nswitch(names, 1) != NULL;
}
/*****************************************************************************
* cl_find_match
* Inputs:
* char *names[]: array of alternative switch or option names
* int nnames: number of alternative switch or option names
* Effect:
* looks for command line switch that matches one of names
* Returns:
* index of switch if found, argc if not found
*****************************************************************************/
private int cl_find_match(names, nnames)
char *names[];
int nnames;
{
int j; /* loop counter */
for (j = 0; j < argc; j++) {
if (cl_find_string(argv[j], names, nnames) < nnames) return j;
}
return argc;
}
/*****************************************************************************
* cl_find_string
* Inputs:
* char *s: string to find
* char *names[]: array of strings
* int nnames: number of strings
* Effect:
* looks for s in names
* Returns:
* index of s in names if found, nnames if not found
*****************************************************************************/
private int cl_find_string(s, names, nnames)
char *s;
char *names[];
int nnames;
{
int i; /* loop counter */
for (i = 0; i < nnames; i++) {
if (strcmp(s, names[i]) == 0) {
return i;
}
}
return nnames;
}
/*****************************************************************************
* cl_ready_check
* Effect:
* halt program if cl_rdy is not true.
*****************************************************************************/
private void cl_ready_check()
{
if (!cl_rdy) {
fprintf(stderr,
"Internal error: cl_init was not called, see cmdline.c\n");
exit(1);
}
}